//===============================================================================
// @ IvLCG64.h
// 
// Linear congruential class using 64-bit arithmetic
// ------------------------------------------------------------------------------
// Copyright (C) 2008-2015 by James M. Van Verth and Lars M. Bishop.
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This RNG avoids issues with overflow by using 64-bit integers and then shifting
// down to a 32-bit integer.  
//
//===============================================================================

#pragma once

#include "IvTypes.h"

//-------------------------------------------------------------------------------
//-- Function Prototypes --------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
//-- Classes --------------------------------------------------------------------
//-------------------------------------------------------------------------------

class IvLCG64
{
public:
    IvLCG64( UInt64 seed, UInt64 a = 2862933555777941757LL, UInt64 c = 1 );

    UInt32 Random();
    float  RandomFloat();
    inline UInt32 MaxRand() { return UInt32(0xffffffff); }

private:
    UInt64 mSeed;
    UInt64 mA;
    UInt64 mC;
};

//-------------------------------------------------------------------------------
//-- Inline Functions -----------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
// @ IvLCG64::IvLCG64()
//-------------------------------------------------------------------------------
// Constructor
//-------------------------------------------------------------------------------
inline
IvLCG64::IvLCG64( UInt64 seed, UInt64 a, UInt64 c )
{
    mSeed = seed;
    mA = a;
    mC = c;
}

//-------------------------------------------------------------------------------
// @ IvLCG64::Random()
//-------------------------------------------------------------------------------
// Return random integer
//-------------------------------------------------------------------------------
inline UInt32
IvLCG64::Random()
{
    mSeed = mSeed*mA + mC;
    return UInt32(mSeed >> 32);
}

//-------------------------------------------------------------------------------
// @ IvLCG64::RandomFloat()
//-------------------------------------------------------------------------------
// Return random floating point number in range [0,1)
//-------------------------------------------------------------------------------
inline float  
IvLCG64::RandomFloat()
{
    union
    {
        UInt32 mI;
        float  mF;
    } floatConv;
    floatConv.mI = 0x3f800000 | (Random() >> 9);
    float f = floatConv.mF - 1.0f;
    return f;
}
